#include <psp2/ctrl.h>

#include "scec2c.h"
#include "menu.h"
#include "scr_print.h"
#include "utils.h"
#include "config.h"
#include "main.h"

/* 要显示的列表条目个数，弹窗高度由此动态获取 */
#define MAX_ITEMS_DRAW_NUM 12u

#define TITLE_PADDING_L 10u
#define TITLE_PADDING_T 8u
#define TITLE_HEIGHT (fontGetFontSize() + TITLE_PADDING_T * 2)

#define ITEMVIEW_PADDING_L 10u
#define ITEMVIEW_PADDING_T 3u
#define ITEMVIEW_HEIGHT (fontGetFontSize() + ITEMVIEW_PADDING_T * 2)

#define LISTVIEW_PADDING_L 0u
#define LISTVIEW_PADDING_T 6u
#define LISTVIEW_HEIGHT (ITEMVIEW_HEIGHT * MAX_ITEMS_DRAW_NUM + LISTVIEW_PADDING_T * 2)

#define WINDOW_PADDING 0u
#define WINDOW_WIDTH 250u
#define WINDOW_HEIGHT (TITLE_HEIGHT * 2 + LISTVIEW_HEIGHT + WINDOW_PADDING * 2)
#define WINDOW_SX ((scrPrintGetScreenWidth() - WINDOW_WIDTH) / 2)
#define WINDOW_SY ((scrPrintGetScreenHeight() - WINDOW_HEIGHT) / 2)
#define WINDOW_DX (WINDOW_SX + WINDOW_WIDTH)
#define WINDOW_DY (WINDOW_SY + WINDOW_HEIGHT)

#define TITLE_SX (WINDOW_SX + WINDOW_PADDING)
#define TITLE_SY (WINDOW_SY + WINDOW_PADDING)
#define TITLE_DX (WINDOW_DX - WINDOW_PADDING)
#define TITLE_DY (TITLE_SY + TITLE_HEIGHT)
#define TITLE_WIDTH (TITLE_DX - TITLE_SX)

#define LISTVIEW_SX (WINDOW_SX + WINDOW_PADDING)
#define LISTVIEW_SY TITLE_DY
#define LISTVIEW_DX (WINDOW_DX - WINDOW_PADDING)
#define LISTVIEW_DY (LISTVIEW_SY + LISTVIEW_HEIGHT)
#define LISTVIEW_WIDTH (LISTVIEW_DX - LISTVIEW_SX)

#define ITEMVIEW_WIDTH (LISTVIEW_WIDTH - LISTVIEW_PADDING_L * 2)

#define TITLE2_SX TITLE_SX
#define TITLE2_SY LISTVIEW_DY
#define TITLE2_DX TITLE_DX
#define TITLE2_DY WINDOW_DY

#define COLOR_WINDOW_BG 0xFF7A4423
#define COLOR_TITLE_BG 0xFFA15135
#define COLOR_TEXT_FG_DEF WHITE
#define COLOR_TEXT_BG_DEF 0
#define COLOR_ITEM_BG_SEL 0xFF4776F1

static char *no_yes_names[] = {
    "否",
    "是",
};

static StrArrayOption no_yes_option = {no_yes_names, sizeof(no_yes_names) / sizeof(char *), COLOR_TEXT_FG_DEF};

IntStepOption turbo_options = {0, 1000, 10, "%d毫秒", COLOR_TEXT_FG_DEF};

OptionMenuItem about_items[] = {
    {"TurboPad New v" BUILD_VERSION, OPTION_TYPE_NONE, ORANGE, NULL, NULL, 0},
    {"\t原作者: Rinnegatamante", OPTION_TYPE_NONE, ORANGE, NULL, NULL, 0},
    {"\t新作者: 一直改", OPTION_TYPE_NONE, ORANGE, NULL, NULL, 0},
    {BUILD_DATE, OPTION_TYPE_NONE, ORANGE, NULL, NULL, 0},
};
OptionMenu about_menu = {"关于", NULL, about_items, sizeof(about_items) / sizeof(OptionMenuItem), 1, 0, 0, 0};

OptionMenuItem main_items[] = {
    {"启用连发", OPTION_TYPE_STR_ARRAY, COLOR_TEXT_FG_DEF, &setting_config.enable_turbo, &no_yes_option, 0},
    {"←", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_left, &turbo_options, 0},
    {"↑", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_up, &turbo_options, 0},
    {"→", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_right, &turbo_options, 0},
    {"↓", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_down, &turbo_options, 0},
    {"×", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_cross, &turbo_options, 0},
    {"○", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_circle, &turbo_options, 0},
    {"□", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_square, &turbo_options, 0},
    {"△", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_triangle, &turbo_options, 0},
    {"Select", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_select, &turbo_options, 0},
    {"Start", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_start, &turbo_options, 0},
    {"L", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_l, &turbo_options, 0},
    {"R", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_r, &turbo_options, 0},
    {"L2", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_l2, &turbo_options, 0},
    {"R2", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_r2, &turbo_options, 0},
    {"L3", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_l3, &turbo_options, 0},
    {"R3", OPTION_TYPE_INT_STEP, COLOR_TEXT_FG_DEF, &setting_config.button_r3, &turbo_options, 0},
    {"重置所有设置", OPTION_TYPE_CALLBACK, COLOR_TEXT_FG_DEF, NULL, resetConfig, 0},
    {"关于", OPTION_TYPE_MENU, COLOR_TEXT_FG_DEF, NULL, &about_menu, 0},
};
OptionMenu main_menu = {"TurboPad按键连发", NULL, main_items, sizeof(main_items) / sizeof(OptionMenuItem), 0, 1, 0, 0};

static OptionMenu *current_menu = &main_menu;

static uint8_t menu_show = 0;

static void optionChangedCallback()
{
}

void updateMenuOptions()
{
}

static void moveUp(OptionMenu *menu)
{
    OptionMenuItem *items = menu->items;
    int *ppos;
    int old_pos, max_pos;

    if (menu->read_only)
    {
        menu->focus_pos = 0;
        ppos = &menu->top_pos;
        max_pos = menu->n_items - MAX_ITEMS_DRAW_NUM;
    }
    else
    {
        ppos = &menu->focus_pos;
        max_pos = menu->n_items - 1;
    }
    if (max_pos < 0)
        max_pos = 0;

    old_pos = *ppos;
    if (old_pos < 0)
        old_pos = 0;
    else if (old_pos > max_pos)
        old_pos = max_pos;
    do
    {
        if (*ppos > 0)
            (*ppos)--;
        else if (menu->move_loop)
            *ppos = max_pos;
    } while (!menu->read_only && *ppos != old_pos &&
             (items[*ppos].type == OPTION_TYPE_NONE ||
              items[*ppos].type == OPTION_TYPE_STR ||
              items[*ppos].type == OPTION_TYPE_INT));

    if (menu->read_only)
        refreshListPosNoFocus(&menu->top_pos, menu->n_items, MAX_ITEMS_DRAW_NUM);
    else
        refreshListPos(&menu->top_pos, &menu->focus_pos, menu->n_items, MAX_ITEMS_DRAW_NUM);
}

static void moveDown(OptionMenu *menu)
{
    OptionMenuItem *items = menu->items;
    int *ppos;
    int old_pos, max_pos;

    if (menu->read_only)
    {
        menu->focus_pos = 0;
        ppos = &menu->top_pos;
        max_pos = menu->n_items - MAX_ITEMS_DRAW_NUM;
    }
    else
    {
        ppos = &menu->focus_pos;
        max_pos = menu->n_items - 1;
    }
    if (max_pos < 0)
        max_pos = 0;

    old_pos = *ppos;
    if (old_pos < 0)
        old_pos = 0;
    else if (old_pos > max_pos)
        old_pos = max_pos;
    do
    {
        if (*ppos < max_pos)
            (*ppos)++;
        else if (menu->move_loop)
            *ppos = 0;
    } while (!menu->read_only && *ppos != old_pos &&
             (items[*ppos].type == OPTION_TYPE_NONE ||
              items[*ppos].type == OPTION_TYPE_STR ||
              items[*ppos].type == OPTION_TYPE_INT));

    if (menu->read_only)
        refreshListPosNoFocus(&menu->top_pos, menu->n_items, MAX_ITEMS_DRAW_NUM);
    else
        refreshListPos(&menu->top_pos, &menu->focus_pos, menu->n_items, MAX_ITEMS_DRAW_NUM);
}

int isShowingMenu()
{
    return menu_show;
}

int openMenu()
{
    scrPrintInit();
    menu_show = 1;
    return 0;
}

int closeMenu()
{
    menu_show = 0;
    scrPrintFinish();
    saveConfig();
    return 0;
}

void drawMenu()
{
    char *name2;
    uint32_t name2_color;
    char name_buf[64];
    int sx, sy, dx, dy;
    int w;
    OptionMenu *menu;
    OptionMenuItem *items;
    void *item_option;
    int item_option_type;

    menu = current_menu;
    items = menu->items;

    /* 设置文字颜色 */
    scrPrintSetBackColor(COLOR_TEXT_BG_DEF);
    scrPrintSetTextColor(COLOR_TEXT_FG_DEF);

    /* 窗口背景 */
    scrPrintRectangle(WINDOW_SX, WINDOW_SY, WINDOW_WIDTH, WINDOW_HEIGHT, COLOR_WINDOW_BG);

    /* 顶部标题 */
    scrPrintRectangle(TITLE_SX, TITLE_SY, TITLE_WIDTH, TITLE_HEIGHT, COLOR_TITLE_BG);
    scrPrintfText(TITLE_SX + TITLE_PADDING_L, TITLE_SY + TITLE_PADDING_T, menu->title);
    w = scrPrintGetTextWidth(g_titleid);
    scrPrintfText(ALIGN_RIGHT(TITLE_DX - TITLE_PADDING_L, w), TITLE_SY + TITLE_PADDING_T, g_titleid);
    /* 底部标题 */
    scrPrintRectangle(TITLE2_SX, TITLE2_SY, TITLE_WIDTH, TITLE_HEIGHT, COLOR_TITLE_BG);
    if (menu->parent)
        scrPrintfText(TITLE2_SX + TITLE_PADDING_L, TITLE2_SY + TITLE_PADDING_T, "%s返回", CTRL_CANCEL_TEXT);
    else
        scrPrintfText(TITLE2_SX + TITLE_PADDING_L, TITLE2_SY + TITLE_PADDING_T, "%s退出", CTRL_CANCEL_TEXT);
    snprintf(name_buf, 16, "%s确定", CTRL_ENTER_TEXT);
    w = scrPrintGetTextWidth(name_buf);
    scrPrintfText(ALIGN_RIGHT(TITLE2_DX - TITLE_PADDING_L, w), TITLE2_SY + TITLE_PADDING_T, name_buf);

    /* 选项列表 */
    sx = LISTVIEW_SX + LISTVIEW_PADDING_L;
    sy = LISTVIEW_SY + LISTVIEW_PADDING_T;
    dx = LISTVIEW_DX - LISTVIEW_PADDING_L;
    dy = LISTVIEW_DY - LISTVIEW_PADDING_T;

    scrPtrintEnableClipping(sx, sy, dx, dy);

    int i;
    for (i = menu->top_pos; i < menu->n_items; i++)
    {
        if (sy >= dy)
            break;

        if (!menu->read_only && i == menu->focus_pos)
            scrPrintRectangle(sx, sy, ITEMVIEW_WIDTH, ITEMVIEW_HEIGHT, COLOR_ITEM_BG_SEL);

        scrPrintSetTextColor(items[i].color);
        if (items[i].name)
            scrPrintfText(sx + ITEMVIEW_PADDING_L, sy + ITEMVIEW_PADDING_T, items[i].name);

        item_option = items[i].option;
        item_option_type = items[i].type;
        name2 = NULL;
        name2_color = items[i].color;

        if (item_option_type == OPTION_TYPE_CB_VOID)
        {
            CbVoidOption *option = (CbVoidOption *)item_option;
            item_option = option->option;
            item_option_type = option->option_type;
        }

        if (item_option_type == OPTION_TYPE_STR)
        {
            StrOption *option = (StrOption *)item_option;
            name2 = option->name;
            name2_color = option->color;
        }
        else if (item_option_type == OPTION_TYPE_STR_ARRAY)
        {
            StrArrayOption *option = (StrArrayOption *)item_option;
            int value = *(items[i].value);
            name2 = option->names[value];
            name2_color = option->color;
        }
        else if (item_option_type == OPTION_TYPE_INT)
        {
            IntOption *option = (IntOption *)item_option;
            int value = *(option->value);
            snprintf(name_buf, 64, option->format, value);
            name2 = name_buf;
            name2_color = option->color;
        }
        else if (item_option_type == OPTION_TYPE_INT_ARRAY)
        {
            IntArrayOption *option = (IntArrayOption *)item_option;
            int value = *(items[i].value);
            int value2 = option->values[value];
            snprintf(name_buf, 64, option->format, value2);
            name2 = name_buf;
            name2_color = option->color;
        }
        else if (item_option_type == OPTION_TYPE_INT_STEP)
        {
            IntStepOption *option = (IntStepOption *)item_option;
            int value = *(items[i].value);
            snprintf(name_buf, 64, option->format, value);
            name2 = name_buf;
            name2_color = option->color;
        }

        if (name2)
        {
            scrPrintSetTextColor(name2_color);
            w = scrPrintGetTextWidth(name2);
            scrPrintfText(ALIGN_RIGHT(dx - ITEMVIEW_PADDING_L, w), sy + ITEMVIEW_PADDING_T, name2);
        }

        sy += ITEMVIEW_HEIGHT;
    }

    scrPtrintDisableClipping();
}

void ctrlMenu(SceCtrlData *ctrl, int negative)
{
    OptionMenu *menu = current_menu;
    OptionMenuItem *items = menu->items;

    readPad(ctrl, negative);

    if (isKeyReleased(CTRL_CANCEL_KEY))
    {
        if (menu->parent)
            current_menu = menu->parent;
        else
            closeMenu();
        goto END;
    }
    else if (isKeyReleased(SCE_CTRL_SQUARE))
    {
        closeMenu();
        goto END;
    }

    if (isKeyPressed(SCE_CTRL_UP))
    {
        moveUp(menu);
    }
    else if (isKeyPressed(SCE_CTRL_DOWN))
    {
        moveDown(menu);
    }

    /* 如果当前列表为只读，跳过变更设置处理 */
    if (menu->read_only)
        goto END;

    void *item_option = items[menu->focus_pos].option;
    int item_option_type = items[menu->focus_pos].type;

    /* 具有函数回调，并且带有选项设置的双重条目 */
    if (item_option_type == OPTION_TYPE_CB_VOID)
    {
        CbVoidOption *option = (CbVoidOption *)item_option;
        item_option = option->option;
        item_option_type = option->option_type;
    }

    if (isKeyPressed(SCE_CTRL_LEFT))
    {
        if (item_option_type == OPTION_TYPE_STR_ARRAY)
        {
            StrArrayOption *option = (StrArrayOption *)item_option;
            if (*(items[menu->focus_pos].value) > 0)
                (*(items[menu->focus_pos].value))--;
            else
                *(items[menu->focus_pos].value) = option->n_names - 1;
            items[menu->focus_pos].option_changed = 1;
        }
        else if (item_option_type == OPTION_TYPE_INT_ARRAY)
        {
            IntArrayOption *option = (IntArrayOption *)item_option;
            if (*(items[menu->focus_pos].value) > 0)
                (*(items[menu->focus_pos].value))--;
            else
                *(items[menu->focus_pos].value) = option->n_values - 1;
            items[menu->focus_pos].option_changed = 1;
        }
        else if (item_option_type == OPTION_TYPE_INT_STEP)
        {
            IntStepOption *option = (IntStepOption *)item_option;
            if (*(items[menu->focus_pos].value) >= option->min + option->step)
                *(items[menu->focus_pos].value) -= option->step;
            else
                *(items[menu->focus_pos].value) = option->max;
            items[menu->focus_pos].option_changed = 1;
        }
    }
    else if (isKeyPressed(SCE_CTRL_RIGHT))
    {
        if (item_option_type == OPTION_TYPE_STR_ARRAY)
        {
            StrArrayOption *option = (StrArrayOption *)item_option;
            if (*(items[menu->focus_pos].value) < option->n_names - 1)
                (*(items[menu->focus_pos].value))++;
            else
                *(items[menu->focus_pos].value) = 0;
            items[menu->focus_pos].option_changed = 1;
        }
        else if (item_option_type == OPTION_TYPE_INT_ARRAY)
        {
            IntArrayOption *option = (IntArrayOption *)item_option;
            if (*(items[menu->focus_pos].value) < option->n_values - 1)
                (*(items[menu->focus_pos].value))++;
            else
                *(items[menu->focus_pos].value) = 0;
            items[menu->focus_pos].option_changed = 1;
        }
        else if (item_option_type == OPTION_TYPE_INT_STEP)
        {
            IntStepOption *option = (IntStepOption *)item_option;
            if (*(items[menu->focus_pos].value) <= option->max - option->step)
                *(items[menu->focus_pos].value) += option->step;
            else
                *(items[menu->focus_pos].value) = option->min;
            items[menu->focus_pos].option_changed = 1;
        }
    }
    else if (isKeyPressed(SCE_CTRL_TRIANGLE))
    {
        if (items[menu->focus_pos].value)
        {
            *(items[menu->focus_pos].value) = 0;
            items[menu->focus_pos].option_changed = 1;
        }
    }
    else if (isKeyPressed(CTRL_ENTER_KEY))
    {
        item_option = items[menu->focus_pos].option;
        item_option_type = items[menu->focus_pos].type;

        if (item_option_type == OPTION_TYPE_CALLBACK)
        {
            int (*callback)() = (int (*)())item_option;
            if (callback)
                callback();
        }
        else if (item_option_type == OPTION_TYPE_CB_VOID)
        {
            CbVoidOption *option = (CbVoidOption *)item_option;
            if (option->callback)
                option->callback();
        }
        else if (item_option_type == OPTION_TYPE_MENU)
        {
            OptionMenu *next = (OptionMenu *)item_option;
            if (next->read_only)
            {
                next->top_pos = next->focus_pos = 0;
            }
            else
            {
                next->top_pos = 0;
                next->focus_pos = -1;
                moveDown(next);
            }
            next->parent = menu;
            current_menu = next;
        }
    }

END:
    /* 如果设置有变更，回调设置变更处理函数 */
    if (items[menu->focus_pos].option_changed)
    {
        optionChangedCallback();
        items[menu->focus_pos].option_changed = 0;
    }

    /* 将hook返回的ctrl->buttons值清空 */
    ctrl->buttons = negative ? 0xFFFFFFFF : 0;
}